package com.tang.crm.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.tang.crm.entity.Module;
import com.tang.crm.entity.Permission;
import com.tang.crm.mapper.ModuleMapper;
import com.tang.crm.mapper.PermissionMapper;
import com.tang.crm.service.ModuleService;
import com.tang.crm.utils.AssertUtil;
import com.tang.crm.vo.TreeVo;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Service
public class ModuleServiceImpl extends ServiceImpl<ModuleMapper, Module> implements ModuleService {

    @Autowired
    private ModuleMapper moduleMapper;

    @Autowired
    private PermissionMapper permissionMapper;


    /**
     * 查询所有的菜单
     * @return
     */
    @Override
    public List<TreeVo> selectAllModule(Integer roleId) {
        // 查询所有的资源列表
        List<TreeVo> treeVoList = moduleMapper.selectAllModule();
        // 查询指定角色已经授权过的资源列表 (查询角色拥有的资源ID)
        List<Integer> permissionIds = permissionMapper.queryRoleHasModuleIdsByRoleId(roleId);
        if (permissionIds != null && permissionIds.size() > 0){
            // 循环所有的资源列表，判断用户拥有的资源ID中是否有匹配的，如果有，则设置checked属性为true
            for (TreeVo treeVo : treeVoList) {
                if (permissionIds.contains(treeVo.getId())){
                    // 如果包含你，则说明角色授权过，设置checked为true
                    treeVo.setChecked(true);
                }
            }
        }
        return treeVoList;
    }

    /**
     * 查询资源列表
     * @return
     */
    @Override
    public Map<String, Object> selectModuleList() {
        Map<String, Object> map = new HashMap<>();
        List<Map<String, Object>> mapList = moduleMapper.selectModuleList();
        map.put("code", 0);
        map.put("msg", "");
        map.put("count", mapList.size());
        map.put("data", mapList);
        return map;
    }

    /**
     * 添加资源
     *  1. 参数校验
     *      模块名称 moduleName
     *          非空，同一层级下模块名称唯一
     *      地址 url
     *          二级菜单（grade=1），非空且同一层级下不可重复
     *      父级菜单 parentId
     *          一级菜单（目录 grade=0）    -1
     *          二级|三级菜单（菜单|按钮 grade=1或2）    非空，父级菜单必须存在
     *      层级 grade
     *          非空，0|1|2
     *      权限码 optValue
     *          非空，不可重复
     *  2. 设置参数的默认值
     *      是否有效 isValid    1
     *      创建时间createDate  系统当前时间
     *      修改时间updateDate  系统当前时间
     *  3. 执行添加操作，判断受影响的行数
     * @param module
     */
    @Override
    @Transactional
    public void saveModule(Module module) {
        /* 参数校验 */
        // 模块名称 moduleName 是否为空
        AssertUtil.isTrue(StringUtils.isBlank(module.getModuleName()), "模块名称不能为空");
        // 层级 grade 非空，0|1|2
        Integer grade = module.getGrade();
        AssertUtil.isTrue(grade == null || !(grade == 0 || grade == 1 || grade == 2), "菜单层级不合法");
        // 模块名称 moduleName  同一层级下模块名称唯一
        AssertUtil.isTrue(null != moduleMapper.selectModuleByGradeAndModuleName(grade
                , module.getModuleName()), "该层级下模块名称已存在");
        // 如果是二级菜单 （grade=1)
        if (grade == 1){
            // 地址 url   二级菜单（grade=1），非空
            AssertUtil.isTrue(StringUtils.isBlank(module.getUrl()), "URL不能为空");
            // 地址 url   二级菜单（grade=1），且同一层级下不可重复
            AssertUtil.isTrue(null != moduleMapper.selectModuleByGradeAndUrl(grade, module.getUrl()), "URL不可重复");
        }
        // 父级菜单 parentId    一级菜单（目录 grade=0）    -1
        if (grade == 0){
            module.setParentId(-1);
        }
        // 父级菜单 parentId    二级|三级菜单（菜单|按钮 grade=1或2）    非空，父级菜单必须存在
        if (grade != 0){
            // 非空
            AssertUtil.isTrue(null == module.getParentId(), "父级菜单不能为空");
            // 父级菜单必须存在 (将父级菜单的ID作为主键，查询资源记录)
            LambdaQueryWrapper<Module> lambdaQueryWrapper = new LambdaQueryWrapper<>();
            lambdaQueryWrapper.eq(Module::getId, module.getParentId());
            AssertUtil.isTrue(null == moduleMapper.selectOne(lambdaQueryWrapper), "请指定正确的父级菜单");
        }
        // 权限码 optValue     非空
        AssertUtil.isTrue(null == module.getOptValue(), "权限码不能为空");
        // 权限码 optValue     不可重复
        AssertUtil.isTrue(null != moduleMapper.selectModuleByOptValue(module.getOptValue()), "该权限码已存在");
        /* 设置参数的默认值  */
        // 是否有效 isValid    1
        module.setIsValid(1);
        // 创建时间createDate  系统当前时间
        module.setCreateDate(new Date());
        // 修改时间updateDate  系统当前时间
        module.setUpdateDate(new Date());
        /* 执行添加操作，判断受影响的行数 */
        AssertUtil.isTrue(moduleMapper.insert(module) != 1, "添加资源失败");
    }

    /**
     * 修改资源
     *  1. 参数校验
     *      id
     *          非空，数据存在
     *      层级 grade
     *          非空 0|1|2
     *      模块名称 moduleName
     *          非空，同一层级下模块名称唯一 （不包含当前修改记录本身）
     *      地址 url
     *          二级菜单（grade=1），非空且同一层级下不可重复（不包含当前修改记录本身）
     *      权限码 optValue
     *          非空，不可重复（不包含当前修改记录本身）
     *  2. 设置参数的默认值
     *      修改时间updateDate  系统当前时间
     *  3. 执行更新操作，判断受影响的行数
     * @param module
     */
    @Override
    public void updateModule(Module module) {
        /* 1. 参数校验 */
        // id 非空，数据存在
        // 非空判断
        AssertUtil.isTrue(module.getId() == null, "待更新记录不存在");
        // 数据存在
        AssertUtil.isTrue(null == moduleMapper.selectById(module.getId()), "待更新记录不存在");
        // 层级 grade  非空 0|1|2
        Integer grade = module.getGrade();
        AssertUtil.isTrue(grade == null || !(grade == 0 || grade == 1 || grade == 2), "菜单层级不合法");
        // 模块名称 moduleName      非空，同一层级下模块名称唯一 （不包含当前修改记录本身）
        AssertUtil.isTrue(StringUtils.isBlank(module.getModuleName()), "模块名称不能为空");
        // 同一层级下模块名称唯一
        Module moduleData = moduleMapper.selectModuleByGradeAndModuleName(grade, module.getModuleName());
        if (moduleData != null){
            AssertUtil.isTrue(!moduleData.getId().equals(module.getId()), "该层级下菜单名已存在");
        }
        // 地址 url   二级菜单（grade=1），非空且同一层级下不可重复（不包含当前修改记录本身）
        if (grade == 1){
            AssertUtil.isTrue(StringUtils.isBlank(module.getUrl()), "URL地址不能为空");
            // 通过层级与菜单URl查询资源对象
            moduleData = moduleMapper.selectModuleByGradeAndUrl(grade, module.getUrl());
            // 判断是否存在
            if (moduleData != null){
                AssertUtil.isTrue(!moduleData.getId().equals(module.getId()), "该层级下URL地址已存在");
            }
        }
        // 权限码 optValue     非空，不可重复（不包含当前修改记录本身）
        AssertUtil.isTrue(StringUtils.isBlank(module.getOptValue()), "授权码不能为空");
        // 通过权限码查询资源对象
        moduleData = moduleMapper.selectModuleByOptValue(module.getOptValue());
        // 判断是否存在
        if (moduleData != null){
            AssertUtil.isTrue(!moduleData.getId().equals(module.getId()), "该授权码已存在");
        }
        /* 设置参数的默认值 */
        // 修改时间updateDate  系统当前时间
        moduleData.setUpdateDate(new Date());
        /* 执行更新操作，判断受影响的行数 */
        AssertUtil.isTrue(moduleMapper.insert(module) != 1, "更新资源失败");
    }

    /**
     * 删除资源
     *  1. 判断删除的记录是否存在
     *  2. 如果当前资源存在子记录，则不可删除
     *  3. 删除资源时，将对应的权限表的记录也删除（判断权限表中是否存在关联数据，如果存在，则删除）
     *  4. 执行删除（更新）操作，判断受影响的行数
     * @param moduleId
     */
    @Override
    @Transactional
    public void deleteModule(Integer moduleId) {
        // 判断删除的记录是否存在
        AssertUtil.isTrue(null == moduleId, "待删除的记录不存在");
        AssertUtil.isTrue(null == moduleMapper.selectById(moduleId), "待删除的记录不存在");
        // 如果当前资源存在子记录，则不可删除
        Integer count = moduleMapper.countByParentId(moduleId);
        // 如果存在子记录，则不可删除
        AssertUtil.isTrue(count > 0, "该资源存在子记录，不可删除");
        // 通过资源id查询权限表中是否存在数据
        count = permissionMapper.countByModuleId(moduleId);
        // 判断是否存在，存在则删除
        if (count > 0){
            // 删除指定资源ID的权限记录
            permissionMapper.deleteByModuleId(moduleId);
        }
        // 执行删除操作
        AssertUtil.isTrue(moduleMapper.deleteById(moduleId) != 1, "删除资源失败");
    }
}
